<?php
namespace bxd\lib\db;

/**
 * The MIT License
 *
 * Copyright (c) <year> <copyright holders>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * Classe base per effettuare la connessione al database tramite un'istanza precedentemente
 * configurata della classe config\DbConfig
 *
 * @author Damiano Ciarla
 * @package lib
 * @subpackage db/conn
 */
class DbConn
{
	/**
	 * Lista delle connessione \PDO istanziate
	 *
	 * @var array Lista delle connessione
	 */
	protected $connections = array();

	/**
	 * Nome della connessione di default da utilizzare nell'esecuzione delle query
	 *
	 * @var string Nome della connessione
	 */
	protected $defaultConnection;

	/**
	 * Apre la connessione al database tramite i parametri settati nell'istanza config\DbConfig
	 *
	 * @param config\DbConfig $dbConf Istanza della classe config\DbConfig con i valori settati per aprire la connessione al database
	 */
	public function __construct(config\DbConfig $dbConf = null)
	{
	 	if($dbConf !== null)
		{
			$this->connections[$dbConf->connectionName]['connection'] = null;
			$this->connections[$dbConf->connectionName]['config'] = $dbConf;

			if ($this->defaultConnection === null)
				$this->defaultConnection = $dbConf->connectionName;
			
			$this->_execConnection($dbConf);
		}
	}

	/**
	 * Metodo che aggiunge una nuova connessione alla lista di quelle disponibili
	 *
	 * @param config\DbConfig $dbConf Istanza della classe config\DbConfig con i valori settati per aprire la connessione al database
	 * @param boolean $isDefault true|false Imposta se la connessione che si sta aggiungendo è la connessione predefinita
	 * @param boolean $connectNow true|false Se true la connessione viene aperta senza usare separatamente il metodo connect
	 */
	public function addConnect(config\DbConfig $dbConfig, $isDefault = false, $connectNow = false)
	{
		$this->connections[$dbConfig->connectionName]['connection'] = null;
		$this->connections[$dbConfig->connectionName]['config'] = $dbConfig;

		if($isDefault)
			$this->defaultConnection = $dbConfig->connectionName;

		if($connectNow)
			$this->_execConnection($dbConfig);
	}

	/**
	 * Metodo che apre la connessione di una determinata configurazione o di tutte quelle presenti nella lista
	 *
	 * @param string $connectionName Nome della connessione
	 * @param boolean $isDefault true|false Imposta se la connessione che si sta aggiungendo è la connessione predefinita
	 */
	public function connect($connectionName = null, $isDefault = false)
	{
		if($connectionName !== null)
		{
			if(!array_key_exists($connectionName, $this->connections))
				throw new exception\DbException($connectionName, exception\DbException::CONNECTION_NAME_NOT_FOUND);

			if($this->connections[$connectionName]['connection'] === null)
			{
				if($isDefault)
					$this->defaultConnection = $connectionName;

				$this->_execConnection($this->connections[$connectionName]['config']);
			}
		}
		else
		{
			foreach($this->connections as $connectionName => $properties)
			{
				if($properties['connection'] === null)
					$this->_execConnection($properties['config']);
			}
		}
	}

	/**
	 * Metodo che chiude tutte le connessioni o una connessione specifica
	 *
	 * @param string $connectionName Nome della connessione
	 */
	public function close($connectionName = null)
	{
		if($connectionName !== null)
		{
			if(!array_key_exists($connectionName, $this->connections))
				throw new exception\DbException($connectionName, exception\DbException::CONNECTION_NAME_NOT_FOUND);

			$this->connections[$connectionName]['connection'] = null;
		}
		else
		{
			foreach($this->connections as $connectionName => $properties)
				$this->connections[$connectionName]['connection'] = null;
		}
	}

	/**
	 * Metodo utilizzato per impostare una connessione predefinita per l'esecuzione delle query
	 * passando come parametro il nome della connessione
	 *
	 * @param string $connectionName Nome della connessione
	 */
	public function useConnection($connectionName)
	{
		if($connectionName !== null && !array_key_exists($connectionName, $this->connections))
			throw new exception\DbException($connectionName, exception\DbException::CONNECTION_NAME_NOT_FOUND);
		
		$this->defaultConnection = $connectionName;
	}

	/**
	 * Metodo utilizzato per verificare la presenza di una connessione
	 *
	 * @param string $connectionName Nome della connessione
	 *
	 * @return boolean
	 */
	public function checkIfExistsConnection($connectionName)
	{
		if(!array_key_exists($connectionName, $this->connections))
			return false;
		
		return true;
	}
	
	/**
	 * Metodo che restituisce la connessione di default se attiva
	 *
	 * @return boolean $returnConfig Valore booleano che imposta se deve essere restituita la configurazione o la connessione
	 * 
	 * @return \PDO|config\DbConfig Connessione di default o configurazione
	 */
	public function getConnection($returnConfig = false)
	{
		if($this->defaultConnection === null)
			throw new exception\DbException("getConnection", exception\DbException::CONNECTION_NOT_FOUND);

		if($this->connections[$this->defaultConnection]['connection'] === null)
			throw new exception\DbException($this->defaultConnection, exception\DbException::DEFAULT_CONNECTION_IS_NOT_ACTIVE);

		return $this->connections[$this->defaultConnection][(($returnConfig) ? 'config' : 'connection')];
	}
	
	/**
	 * Metodo che restituisce la configurazione di una determinata connessione
	 *
	 * @return string $connectionName Nome della connessione
	 *
	 * @return config\DbConfig
	 */
	public function getConfigByName($connectionName)
	{
		if(!isset($this->connections[$connectionName]['config']))
			throw new exception\DbException($connectionName, exception\DbException::CONNECTION_NAME_NOT_FOUND);
		
		return $this->connections[$connectionName]['config'];
	}

	/**
	 * Metodo che crea la connessione \PDO in base ai parametri settati nel config\DbConfig
	 *
	 * @param config\DbConfig $dbConf Istanza della classe config\DbConfig con i valori settati per aprire la connessione al database
	 */
	private function _execConnection(config\DbConfig $config)
	{
		$dsn		= $config->type . ":host=" . $config->host . ";dbname=" . $config->dbname;
		$username	= $config->username;
		$passwd		= $config->passwd;

		if($config->persistent !== null)
			$options[\PDO::ATTR_PERSISTENT] = $config->persistent;
		
		if($config->charset !== null && $config->collate !== null)
		{
			$options[\PDO::MYSQL_ATTR_INIT_COMMAND] = "SET NAMES " . $config->charset . " COLLATE " . $config->collate;
		}
		elseif($config->charset !== null)
		{
			$options[\PDO::MYSQL_ATTR_INIT_COMMAND] = "SET NAMES " . $config->charset;
		}

		try
		{
			$this->connections[$config->connectionName]['connection'] = new \PDO($dsn, $username, $passwd, $options);
			$this->connections[$config->connectionName]['connection']->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
		}
		catch(\PDOException $e)
		{
			throw new exception\DbException($e->getMessage(), exception\DbException::DB_CONNECTION_ERROR);
		}
	}
}
?>